package state

import (
	"github.com/cnfinder/svm/common"
	"github.com/cnfinder/svm/crypto"
	"math/big"
)

/*
store 用来数据的操作。  DAO

// 这里的账户 都是 合约账户
 */

//
type accountData struct {
	Nonce    uint64      `json:"nonce,omitempty"`
	Balance  *big.Int    `json:"balance,omitempty"`
	Root     common.Hash `json:"root,omitempty"` // merkle root of the storage trie
	CodeHash []byte      `json:"code_hash,omitempty"`   // 合约的 代码HASH , runtime的hash
}

// -- 数据操作层: 账户包含（普通账户和合约账户）
type accountObject struct {
	Address      common.Address              `json:"address,omitempty"`  //合约地址
	AddrHash     common.Hash                 `json:"addr_hash,omitempty"` // hash of ethereum address of the account
	ByteCode     []byte                      `json:"byte_code,omitempty"`
	Data         accountData                 `json:"data,omitempty"`
	CacheStorage map[common.Hash]common.Hash `json:"cache_storage,omitempty"` // 用于缓存存储的变量
}




// --------accountObject api

func newAccountObject(addr common.Address,accountData accountData)  *accountObject{
	return &accountObject{
		Address:addr,
		Data:accountData,
	}
}
func (accObj *accountObject) SubBalance(amount *big.Int)  {
	o:=new(big.Int)
	res:=o.Sub(accObj.Data.Balance,amount)

	accObj.Data.Balance=res
}

func (accObj *accountObject) Nonce() uint64 {
	return accObj.Data.Nonce
}

func  (accObj *accountObject) AddBalance(amount *big.Int)  {

	o:=new(big.Int)

	res:=o.Add(accObj.Data.Balance,amount)

	accObj.Data.Balance=res
}

func (accObj *accountObject) Balance()  *big.Int {
	return accObj.Data.Balance
}

func (accObj *accountObject) SetNonce(nonce uint64) {
	accObj.Data.Nonce=nonce
}

func (accObj *accountObject)  CodeHash() []byte{
	return accObj.Data.CodeHash
}

func (accObj *accountObject)  Code()  []byte{
	return accObj.ByteCode
}

func (accObj *accountObject) GetStorageState(key *common.Hash) common.Hash{
	return accObj.CacheStorage[*key]
}

func (accObj *accountObject) SetCode(addr common.Address, code []byte){
	// 根据 addr 和nonce 计算
	accObj.Address=addr
	accObj.ByteCode=code

	accObj.Data.CodeHash = crypto.Keccak256(code) //来源 EVM.Create

}

func (accObj *accountObject) SetStorageState(key common.Hash, value common.Hash) {
	accObj.CacheStorage[key]=value
}


func (accObj *accountObject)  Empty() bool {
	if len(accObj.CacheStorage)==0{
		return true
	}
	return false
}

// 根据 ByteCode 判断是否是合约账户
func (accObj *accountObject) IsContract() bool {

	if len(accObj.ByteCode)==0{
		return false
	}
	return true
}
//---------accountObject api end



